package com.library.logging.modules.operationlog.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.library.common.enums.LogTypeEnum;
import com.library.common.util.SystemUtils;
import com.library.logging.annotation.LogSys;
import com.library.logging.modules.operationlog.entity.OperationLog;
import com.library.logging.modules.operationlog.vo.OperationLogVO;
import com.library.logging.modules.operationlog.bo.OperationLogPage;
import com.library.logging.modules.operationlog.mapper.OperationLogMapper;
import com.library.logging.modules.operationlog.service.OperationLogService;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.library.common.util.PageCovertUtil;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.BindingResult;
import org.springframework.web.multipart.MultipartFile;

import java.security.Principal;
import java.util.Collection;
import java.util.Map;


/**
 * @Author xyh
 * @Desc 操作日志表(OperationLog)表服务实现类
 * @Date 2023-10-05 14:42:51
 */

@Service("operationLogService")
public class OperationLogServiceImpl extends ServiceImpl<OperationLogMapper, OperationLog> implements OperationLogService {

    @Override
    public IPage<OperationLogVO> queryByPage(OperationLogPage page) {
        // 查询条件
        LambdaQueryWrapper<OperationLog> queryWrapper = new LambdaQueryWrapper<>();
        if (StrUtil.isNotEmpty(page.getRequestIp())) {
            queryWrapper.eq(OperationLog::getRequestIp, page.getRequestIp());
        }
        if (StrUtil.isNotEmpty(page.getUsername())) {
            queryWrapper.eq(OperationLog::getUsername, page.getUsername());
        }
        queryWrapper.eq(OperationLog::getLogType, LogTypeEnum.DO_LOG.getCode());
        queryWrapper.orderByDesc(OperationLog::getCreateTime);
        // 查询分页数据
        Page<OperationLog> operationLogPage = new Page<OperationLog>(page.getCurrent(), page.getSize());
        IPage<OperationLog> pageData = baseMapper.selectPage(operationLogPage, queryWrapper);

        //转换成vo
        IPage<OperationLogVO> records = PageCovertUtil.pageVoCovert(pageData, OperationLogVO.class);
        if (CollUtil.isNotEmpty(records.getRecords())) {
            records.getRecords().forEach(r -> {
                r.setRequestIp("演示环境，不对外展示");
                r.setAddress("演示环境，不对外展示");
            });
        }
        return records;
    }

    @Override
    public IPage<OperationLogVO> queryLoginLogByPage(OperationLogPage page) {
        // 查询条件
        LambdaQueryWrapper<OperationLog> queryWrapper = new LambdaQueryWrapper<>();
        if (StrUtil.isNotEmpty(page.getRequestIp())) {
            queryWrapper.eq(OperationLog::getRequestIp, page.getRequestIp());
        }
        if (StrUtil.isNotEmpty(page.getUsername())) {
            queryWrapper.eq(OperationLog::getUsername, page.getUsername());
        }
        queryWrapper.eq(OperationLog::getLogType, LogTypeEnum.LOGIN_SUCCESS.getCode())
                .or()
                .eq(OperationLog::getLogType, LogTypeEnum.LOGIN_OUT.getCode());

        queryWrapper.orderByDesc(OperationLog::getCreateTime);
        // 查询分页数据
        Page<OperationLog> operationLogPage = new Page<OperationLog>(page.getCurrent(), page.getSize());
        IPage<OperationLog> pageData = baseMapper.selectPage(operationLogPage, queryWrapper);

        //转换成vo
        IPage<OperationLogVO> records = PageCovertUtil.pageVoCovert(pageData, OperationLogVO.class);
        if (CollUtil.isNotEmpty(records.getRecords())) {
            records.getRecords().forEach(r -> {
                r.setRequestIp("演示环境，不对外展示");
                r.setAddress("演示环境，不对外展示");
            });
        }
        return records;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void insert(HttpServletRequest request, JoinPoint joinPoint, String result) {
        // 从切面织入点处通过反射机制获取织入点处的方法
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        LogSys annotation = signature.getMethod().getAnnotation(LogSys.class);
        Principal principal = request.getUserPrincipal();

        OperationLog log = new OperationLog();
        log.setRequestIp(SystemUtils.getIp(request));
        log.setAddress(SystemUtils.getAddressInfo(log.getRequestIp()));
        log.setLogType(annotation.logType().getCode());
        log.setBrowser(SystemUtils.getBrowser(request));
        log.setDescription(annotation.value());
        log.setParams(composeString(joinPoint.getArgs()));
        // 方法地址
        String methodName = joinPoint.getTarget().getClass().getName() + "." + signature.getName() + "()";
        log.setMethods(methodName);
        if (principal != null) {
            log.setUsername(principal.getName());
        }
        log.setReturnValue(result);
        save(log);
    }

    /**
     * 请求参数拼装
     */
    private String composeString(Object[] paramsArray) {
        String params = "";
        if (paramsArray != null && paramsArray.length > 0) {
            for (Object o : paramsArray) {
                if (null != o && !isFilterObject(o)) {
                    try {
                        Object jsonObj = JSON.toJSON(o);
                        params += jsonObj.toString() + " ";
                    } catch (Exception e) {
                        log.error("拼接失败，错误信息：{}", e);
                    }
                }
            }
        }
        return params.trim();
    }

    public boolean isFilterObject(final Object o) {
        Class<?> clazz = o.getClass();
        if (clazz.isArray()) {
            return clazz.getComponentType().isAssignableFrom(MultipartFile.class);
        } else if (Collection.class.isAssignableFrom(clazz)) {
            Collection collection = (Collection) o;
            for (Object value : collection) {
                return value instanceof MultipartFile;
            }
        } else if (Map.class.isAssignableFrom(clazz)) {
            Map map = (Map) o;
            for (Object value : map.entrySet()) {
                Map.Entry entry = (Map.Entry) value;
                return entry.getValue() instanceof MultipartFile;
            }
        }
        return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse
                || o instanceof BindingResult;
    }


}
